easy接口的选项的配置

3 curl_easy_setopt()

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);

这个接口是用来定制发送细节的,我们大部分逻辑需要通过这个接口传给“curl easy handle”在下一步的curl_easy_perform()中进行传输。

定制请求行 --- CURLOPT_URL

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_URL, char *URL);

该选项CURLOPT_URL用来设置请求行。该选项是 唯一必须 设置的选项。

其中URL需遵循以下格式:

[scheme://]host[:port]/path

libcurl 不会对传入的url进行验证,因此即使传入的是一个很离谱的字符串,接口的返回值也一样会是CURLE_OK

scheme

如果传入的URL没有定义scheme,那么libcurl会根据host进行猜测,如果host的域名符合DICT, FTP, IMAP, LDAP, POP3 或者 SMTP,那么对应的scheme会被使用,否则的话,会用http。默认的scheme可以用CURLOPT_DEFAULT_PROTOCOL进行定义。

如果scheme中设置的协议不是libcurl所支持的,那么在后续的调用curl_easy_perform会返回CURLE_UNSUPPORTED_PROTOCOL

host

host部分包含需要访问的服务地址,可以是hostname也可以是IP,对于一些类型的协议,可以用以下格式指定用户名和密码:

scheme:\\user:password;options@host:port\path

port

port部分为可选配置,如果不设置的话,libcurl会根据协议的类型来选择端口,如http默认使用80端口。 另外,开发者还可以使用CURLOPT_PORT来指定端口。

定制HTTP方法 --- CURLOPT_HTTPGET,CURLOPT_PUT,CURLOPT_POST,CCURLOPT_UPLOAD

这三个选项用来指定http请求的方法,需要注意的是Get方法的字符和其他方法的格式有所不同。

需要使用某种方法时,需将其选项置为1L(long)。如:

curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);

CURLOPT_HTTPGET,配置发送http Get请求,若被置为1,则CURLOPT_UPLOADCURLOPT_NOBODY会被自动置成0.

CURLOPT_POST,配置发送http Post请求。

CURLOPT_PUT在最新版本中已经被弃用,替代版本是CURLOPT_UPLOAD。 在HTTP1.1中,可以通过块传输的方式来传输文件或者数据,在这种情况下,无需指定文件的大小。(需要指定http头Transfer-Encoding: chunked) 如果采用其他方式,或者使用HTTP1.0,则必须指定文件大小。

定制HTTP头部 --- CURLOPT_HTTPHEADER

以发送http请求为例,如果我们想在在发送的请求中带上一些http头,那么我们就需要调用:

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPHEADER, struct curl_slist *headers);

使用CURLOPT_HTTPHEADER的option,把定制的http头放在struct curl_slist *headers中。

关于struct curl_slist *headers,curl提供了一组API进行操作:

  • curl_slist_append()
  • curl_slist_free_all()
#include <curl/curl.h>

struct curl_slist *curl_slist_append(struct curl_slist * list, const char * string );

该接口用来向curl_slist添加新的项目。比如说,我想添加一个自定义的头“x-hello-world”,对应的代码应该是如下:

 struct curl_slist* slist = NULL;
 slist = curl_slist_append(slist, "x-hello-world: 1");

这样,最终发出来的报文中就会包含x-hello-world:1头,如果在这一步中设置了一个默认的http头,那么这个定制的头会覆盖默认的http头。

如果在这步设置了一个不完整的http头(这个头默认是存在的),如:Accept:(缺少数据),那么这个头会被在报文中被去掉。

如果想加一个没有内容的http头,需要使用这样的格式:MyHeader;

这些添加的头不能以\r\n(CRLF)结尾,因为在添加的过程中,函数会自动地给每个头加上\r\n

请求行需要用3.1中介绍的CURLOPT_URL进行设置。

另外一个接口:

#include <curl/curl.h>

void curl_slist_free_all(struct curl_slist * list);

这个接口用来释放一个curl_slist中所有的节点。 需要注意的是,在整个请求的发送过程中,该链表的内存会被libcurl直接使用,所有只有在传输全部完成的情况下,才可以调用curl_slist_free_all()释放该链表的内存。

上传文件

上传文件时需要用到:

  • CURLOPT_READFUNCTION
  • CURLOPT_READDATA

其中,CURLOPT_READFUNCTION 用来指定设置http body时的回调函数,该函数需要开发者实现,需要遵守如下原型:

size_t read_callback(char* buffer, size_t size, size_t nitems, void* instream);

该回调函数表明,要从源instream向目标缓冲buffer中写入size * nitems bytes的数据。 前三个参数由libcurl在curl_easy_perform过程中输入,最后一个参数往往是输入的数据源,使用CURLOPT_READDATA选项进行设置。

回调函数的返回值表示此次实际读取的数据大小,如果返回0的话,会向libcurl库发生EOF的信号,这会停止当前的传输过程。 如果试图直接返回0值来使手动停止当前传输过程,服务端对应的处理程序会Hung住,因为服务端并没有收到指定的数据量。 正确的停止当前传输过程的方法是返回CURL_READFUNC_ABORT

使用SSL

配置使用SSL时,需要用到CURLOPT_SSLVERSION来指定SSL的版本,目前使用CURL_SSLVERSION_TLSv1。 同时,如果使用的是自签名的证书,需要把CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST都置成0L。这样的话,使用自定义的证书进行SSL连接的时候,就不会检测证书是否是正规CA颁发的,也不会检查该证书是否是颁发给该host的。

如果想要在非http协议中使用SSL,需要设置CURLOPT_USE_SSL来进行配置。

使用代理

如果想要在连接中使用代理,需要设置下列选项中的一个或者多个:

  • CURLOPT_PROXY
  • CURLOPT_PROXYPORT
  • CURLOPT_PROXYTYPE

CURLOPT_PROXY选项用来指定代理的地址,其scheme格式类似CURLOPT_URL的规定,可以在其中指定协议类型,host,端口,用户名密码等。 如果不希望在这个scheme中指定太多内容的话,则需要其他选项来进行配置。

在代理有密码的情况下,如果不希望把密码直接写在代理地址的scheme中,则需要设置:

  • CURLOPT_PROXYUSERPWD

其scheme为 [user]:[password]

接受数据

接受数据需要配置如下选项:

  • CURLOPT_WRITEFUNCTION
  • CURLOPT_WRITEDATA

配置CURLOPT_WRITEFUNCTION来指定处理接受到的数据的回调函数,该回调函数需要遵循如下原型:

size_t write_callback(char * ptr, size_t size, size_t nmemb, void * userdata);

其中ptr指向接收到数据的内存,该数据的大小为size * nmemb bytes,第四个参数userdata使用CURLOPT_WRITEDATA来指定。 需要指出的是,在windows环境下,如果设置了CURLOPT_WRITEDATA,则必须设置CURLOPT_WRITEFUNCTION,否则会导致程序崩溃。

CURLOPT_WRITEFUNCTION主要用来接收报文Body的数据,但这里的Body范围是可定义的。通过设置选项CURLOPT_HEADER为1,可以把所有header数据放到body中进行处理。

打开调试模式

  • CURLOPT_VERBOSE 将此项设置为1时,打开详细调试模式。默认情况下,调试信息会被发送到标准错误(stderr),可以使用CURLOPT_STDERR设置标准输出。 如果需要所有协议的发送和接收的详情,需要设置CURLOPT_DEBUGFUNCTION

  • CURLOPT_DEBUGFUNCTION

#include <curl/curl.h>

typedef enum {
  CURLINFO_TEXT = 0,
  CURLINFO_HEADER_IN,    /*1*/
  CURLINFO_HEADER_OUT,   /*2*/
  CURLINFO_DATA_IN,      /*3*/
  CURLINFO_DATA_OUT,     /*4*/
  CURLINFO_SSL_DATA_IN,  /*5*/
  CURLINFO_SSL_DATA_OUT, /*6*/
  CURLINFO_END
} curl_infotype;

int debug_callback(CURL* handle,
                   curl_infotype type,
                   char* data,
                   size_t size,
                   void* userptr);

使用CURLOPT_DEBUGFUNCTION时,需要提供一个回调函数,其原型如上所示。只有CURLOPT_VERBOSE被设置的情况下,该回调函数才会取代默认的调试函数起作用。 其参数curl_infotype type会提供当前阶段的信息。 char* data是一个不以\0结尾的字符串,其大小为参数size_t size中所指定的大小。 该函数必须返回0(CURLE_OK)。

杂项

  • CURLOPT_NOSIGNAL 如果将该项设为1,libcurl就不会使用一类函数---任何设有信号处理函数或者可能会收到信号的函数。

  • CURLOPT_CONNECTTIMEOUT 正如该选项名字所示,该选项用来设置建立连接的超时时间。该选项不会对已经建立的连接有任何影响。 如果设其为0,则使用默认值---300秒

  • CURLOPT_TIMEOUT 用来定义传输过程的超时时间。如果设其为0,则永不超时。